package com.mumux.framework.aop.core;

import com.google.common.collect.Lists;
import com.mumux.framework.aop.bean.AopBeanDefinition;
import com.mumux.framework.ioc.bean.BeanDefinition;
import com.mumux.framework.ioc.bean.PropertyArg;
import com.mumux.framework.ioc.utils.ClassUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName XmlAopApplicationContext
 * Description TODO
 * @Author huangjuncong
 * @Date 2019/2/14 0014
 **/
@Slf4j
public class XmlAopApplicationContext extends AopBeanFactoryImpl {

    private String fileName;

    public XmlAopApplicationContext(String fileName) {
        this.fileName = fileName;
    }

    public void init(){
        loadFile();
    }

    private void loadFile(){

        List<AopBeanDefinition> beanDefinitions = getAopBeanDefinitions();

        if(beanDefinitions != null && !beanDefinitions.isEmpty()) {

            for (AopBeanDefinition beanDefinition : beanDefinitions){
                Class<?> clz = ClassUtils.loadClass(beanDefinition.getClassName());
                if(clz == ProxyFactoryBean.class){
                    registerBean(beanDefinition.getName(),beanDefinition);
                }else {
                    registerBean(beanDefinition.getName(),(BeanDefinition) beanDefinition);
                }
            }
        }

    }

    private List<AopBeanDefinition> getAopBeanDefinitions(){
        try{
            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = factory.newDocumentBuilder();
            Document doc = docBuilder.parse(is);
            Element root = doc.getDocumentElement();
            NodeList nodes = root.getChildNodes();
            ArrayList<AopBeanDefinition> beanDefinitionList = Lists.newArrayList();
            // 遍历 <bean> 标签
            for (int i = 0; i < nodes.getLength(); i++) {
                Node node = nodes.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    String id = ele.getAttribute("id");
                    String className = ele.getAttribute("class");
                    String target = ele.getAttribute("target");
                    AopBeanDefinition aopBeanDefinition = AopBeanDefinition.class.newInstance();
                    aopBeanDefinition.setName(id);
                    aopBeanDefinition.setClassName(className);
                    if (StringUtils.isNotBlank(target)){
                        aopBeanDefinition.setTarget(target);
                    }
                    NodeList propertyNodes = ele.getElementsByTagName("property");
                    ArrayList<PropertyArg> propertyArgs = new ArrayList<>();
                    ArrayList<String> interceptorNames = Lists.newArrayList();
                    for (int j = 0; j < propertyNodes.getLength(); j++) {
                        Node propertyNode = propertyNodes.item(j);
                        if (propertyNode instanceof Element) {
                            PropertyArg propertyArg = PropertyArg.class.newInstance();
                            Element propertyElement = (Element) propertyNode;
                            NodeList childNodes = propertyNode.getChildNodes();
                            if (childNodes == null){
                                String name = propertyElement.getAttribute("name");
                                propertyArg.setName(name);
                                String value = propertyElement.getAttribute("value");
                                if (StringUtils.isNotBlank(value)) {
                                    propertyArg.setValue(value);
                                }
                                String ref = propertyElement.getAttribute("ref");
                                if (StringUtils.isNotBlank(ref)) {
                                    propertyArg.setRef(ref);
                                }
                                propertyArgs.add(propertyArg);
                            }
                            for (int k = 0; k < childNodes.getLength(); k++){
                                Node listNode = childNodes.item(k);
                                if (listNode instanceof Element){

                                    NodeList listChild = listNode.getChildNodes();
                                    if (listChild != null){
                                        for (int n = 0; n < listChild.getLength(); n++){
                                            Node interceptorNameNode =  listChild.item(n);
                                            if (interceptorNameNode instanceof Element){
                                                Element interceptorNameElement = (Element) interceptorNameNode;
                                                String interceptorName = interceptorNameElement.getAttribute("bean");
                                                interceptorNames.add(interceptorName);
                                            }
                                        }
                                    }
                                }

                            }

                        }
                    }
                    aopBeanDefinition.setPropertyArgs(propertyArgs);
                    aopBeanDefinition.setInterceptorNames(interceptorNames);
                    beanDefinitionList.add(aopBeanDefinition);
                }
            }
            return beanDefinitionList;
        }catch (Exception e){
            log.error("配置文件解析失败",e);
        }
        return null;
    }



}
